/*
 * ExternalSort.cpp
 *
 *  Created on: Oct 10, 2012
 *      Author: bruno
 */

#include "ExternalSort.h"

ExternalSort::ExternalSort(unsigned int bufferSizeFactor,
		std::string workFile, std::string outputFileName, bool outputInteger)
: heap( new Heap<DICTIONARY_ENTRY, dictionaryEntryComparator>( bufferSizeFactor * 10 ) ),
  fileManager( new FileManager(workFile, bufferSizeFactor, outputFileName, outputInteger) ),
  fileMerger ( new FileMerger() )
{
	this->bufferSizeFactor = bufferSizeFactor;
	input = fileManager->getInput();
}

ExternalSort::~ExternalSort() {
//	delete heap;
//	delete fileManager;
//	delete fileMerger;
//	delete output;
//	delete input;
}

void ExternalSort::loadHeap() {
	for (unsigned int i = 0; input->hasNext() && i < heap->size(); i++) {
		heap->loadItem(input->get());
	}
	heap->heapify();
}

void ExternalSort::sort() {

	loadHeap();

	fileManager->setTempFolderName(std::string("particiones"));

	output = fileManager->getNewTempFile();

	while (input->hasNext()) {
		DICTIONARY_ENTRY dictionaryEntry = input->get();

		if (dictionaryEntryComparator(dictionaryEntry, heap->peekItem()) >= 0) {
			dictionaryEntry = heap->pushAndPopItem(dictionaryEntry);

			output->put(dictionaryEntry);
		} else {
			dictionaryEntry = heap->freezeItem(dictionaryEntry);

			output->put(dictionaryEntry);
		}

		if (heap->size() == 0) {
			output->close();
			output = fileManager->getNewTempFile();
			heap->unfreezeItems();
		}
	}

	size_t heapCount = heap->lenght();

	for (size_t i = 0; i < heapCount; i++) {
		DICTIONARY_ENTRY dictionaryEntry = heap->popItem();
		output->put(dictionaryEntry);
	}

	output->close();

	if (heap->getFreezedItems() > 0) {
		heap->recoverFreezedItems();

		output = fileManager->getNewTempFile();

		size_t heapCount = heap->lenght();
		for (size_t i = 0; i < heapCount; i++) {
			DICTIONARY_ENTRY dictionaryEntry = heap->popItem();
			output->put(dictionaryEntry);
		}

		output->close();
	}

	mergeFiles();

}

void ExternalSort::mergeFiles() {

	IDS_ptr input( fileManager->getNextTempFile() );

	fileManager->setTempFolderName("etapa");

	fileManager->setPrintTmpLevel(true);

	unsigned int batchCount;

	do {

		batchCount = 0;

		do {

			batchCount++;

			for (size_t i = 0; input && i < bufferSizeFactor + 1; i++) {

				fileMerger->addinput( input );

				input = fileManager->getNextTempFile();

			}

			if (batchCount == 1 && !input) {
				output = fileManager->getOutput();
			} else {
				output = fileManager->getNewTempFile();
			}

			fileMerger->setOutput( output );

			fileMerger->mergeFiles();

			fileMerger->clearInputs();

		} while (input);

		fileManager->increaseLevel();

		input = fileManager->getNextTempFile();

	} while (batchCount != 1 && input);
}

int dictionaryEntryComparator(DICTIONARY_ENTRY entry1,
		DICTIONARY_ENTRY entry2) {
	int result = entry1->getRandomKey() - entry2->getRandomKey();
	if (result == 0) {
		result = strcmp(entry1->getTerm(), entry2->getTerm());
	}
	return result;
}

